import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import BScroll from 'better-scroll';
import styled from 'styled-components';
import Loading from '../Loading';
import Loading2 from '../LoadingV2';
import { debounce } from '../../api/utils';

const ScrollContainer = styled.div`
  width: 100%;
  height: 100%;
  overflow: hidden;
`;

const PullUpLoading = styled.div`
  position: relative;
  left: 0;
  right: 0;
  bottom: 5px;
  width: 60px;
  height: 60px;
  margin: auto;
  z-index: 100;
`;

const PullDownLoading = styled.div`
  position: absolute;
  left:0; right:0;
  top: 0px;
  height: 30px;
  margin: auto;
  z-index: 100;
`;

const Scroll = forwardRef((props, ref) => {
  // better-scroll实例对象
  const [bScroll, setBScroll] = useState();
  // current指向初始化bs实例需要的dom元素
  const scrollContainerRef = useRef();

  const {
    direction,
    click,
    refresh,
    bounceTop,
    bounceBottom,
    pullUpLoading,
    pullDownLoading
  } = props;
  const { pullUp, pullDown, onScroll } = props;
  
  let pullUpDebounce = useMemo(() => {
    return debounce(pullUp, 300);
  }, [pullUp]);

  let pullDownDebounce = useMemo(() => {
    return debounce(pullDown, 300);
  }, [pullDown]);

  // 组件渲染完成后执行
  useEffect(() => {
    const scroll = new BScroll(scrollContainerRef.current, {
      scrollX: direction === 'horizental',
      scrollY: direction === 'vertical',
      probeType: 3,
      click,
      bounce: {
        top: bounceTop,
        bottom: bounceBottom
      }
    });
    setBScroll(scroll);
    // 销毁时重置实例
    return () => {
      setBScroll(null);
    };
  }, []);

  // 每次重新渲染刷新实例，防止无法滑动
  useEffect(() => {
    if(refresh && bScroll) {
      bScroll.refresh();
    }
  });

  // 给实例绑定scroll事件
  useEffect(() => {
    if(!bScroll || !onScroll) return;
    bScroll.on('scroll', (scroll) => {
      onScroll(scroll);
    });

    // 销毁时关闭scroll事件
    return () => {
      bScroll.off('scroll');
    };
  }, [onScroll, bScroll]);

  // 上拉到底的事件监听，触发pullUp函数
  useEffect(() => {
    if(!bScroll || !pullUp) return;
    bScroll.on('scrollEnd', () => {
      if(bScroll.y <= bScroll.maxScrollY + 100) {
        pullUpDebounce();
      }
    });

    // 销毁时关闭scrollEnd事件
    return () => {
      bScroll.off('scrollEnd');
    };
  }, [pullUp, pullUpDebounce, bScroll]);

  // 下拉刷新的事件监听，触发pullDown函数
  useEffect(() => {
    if(!bScroll || !pullDown) return;
    bScroll.on('touchEnd', (pos) => {
      if (pos.y > 50) {
        pullDownDebounce();
      }
    });

    // 销毁时关闭scrollEnd事件
    return () => {
      bScroll.off('touchEnd');
    };
  }, [pullDown, pullDownDebounce, bScroll]);

  useEffect(() => {
    if(refresh && bScroll) {
      bScroll.refresh();
    }
  });

  useImperativeHandle(ref, () => ({
    refresh() {
      if(bScroll) {
        bScroll.refresh();
        bScroll.scrollTo(0, 0);
      }
    },
    getBScroll() {
      if(bScroll) {
        return bScroll;
      }
    }
  }));


  const PullUpDisplayStyle = pullUpLoading ? { display: '' } : { display: 'none' };
  const PullDownDisplayStyle = pullDownLoading ? { display: '' } : { display: 'none' };

 

  return (
    <ScrollContainer 
      ref={scrollContainerRef}
    >
      {props.children}
      <PullUpLoading style={PullUpDisplayStyle}>
        <Loading show={true}></Loading>
      </PullUpLoading>
      <PullDownLoading style={PullDownDisplayStyle}>
        <Loading2></Loading2>
      </PullDownLoading>
    </ScrollContainer>
  );
});

// props参数类型限制
Scroll.propTypes = {
  // 滚动的方向
  direction: PropTypes.oneOf(['vertical', 'horizental']),
  // 是否可点击
  click: PropTypes.bool,
  // 是否刷新
  refresh: PropTypes.bool,
  // 滑动触发的回调函数
  onScroll: PropTypes.func,
  // 上拉加载逻辑
  pullUp: PropTypes.func,
  // 下拉刷新逻辑
  pullDown: PropTypes.func,
  // 是否显示上拉loading动画
  pullUpLoading: PropTypes.bool,
  // 是否显示下拉loading动画
  pullDownLoading: PropTypes.bool,
  // 是否支持向上吸顶
  bounceTop: PropTypes.bool,
  // 是否支持向下吸顶
  bounceBottom: PropTypes.bool
};

// props默认参数
Scroll.defaultProps = {
  direction: 'vertical',
  click: true,
  refresh: true,
  onScroll: null,
  pullUp: null,
  pullDown: null,
  pullUpLoading: false,
  pullDownLoading: false,
  bounceTop: true,
  bounceBottom: true
};

export default Scroll;